package com.tushen.task;

import com.tushen.utils.SqlSessionFactoryUtil;
import com.tushen.utils.Utils;
import org.gdal.gdal.gdal;
import org.gdal.ogr.*;
import org.gdal.osr.SpatialReference;

import java.io.*;
import java.sql.Time;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 精细三维浓度场处理
 * 1.获取 lon.csv,lat.csv,dye.csv
 * 2.解析1的文件生成点shp,点个数小于5的不生成，插值会异常
 * 3.调用arcpy用点shp文件插值生成tif
 * 4.将tif文件拷贝至geoserver目录（dyetif2目录已发布好服务）
 * 5.将tif文件名信息插入至pg库dyetif2表中
 * 6.将tif栅格文件出入dye_tif_yyyymmdd中，点线钻取查询用
 * @author likun
 * @version 1.0
 * @date 2020/12/13 4:45 下午
 */
public class Dye3 {

    public static void main(String[] args){
        if(args.length<2){
            System.out.println("plese input filePah and version");
            return;
        }
        String dir=args[0];
        String version=args[1];
        processDye3(dir,version);
    }
    /**
     * 处理三维浓度场数据
     * @param dir 数据文件目录
     * @param version 版本
     */
    public static void processDye3(String dir,String version){
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMddHH");
        Date dt=null;
        int startIndex=dir.lastIndexOf("\\")+1;
        if(startIndex==0){
            startIndex=dir.lastIndexOf("/")+1;
        }
        String dtmstr=dir.substring(startIndex);
        try {
            dt=  simpleDateFormat.parse(dtmstr);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("文件路径中时间格式不对，需要yyyyMMddHH格式");
            return;
        }
        String fileSep=java.io.File.separator;
        String pathLont=dir+fileSep+"x.csv";
        String pathLat=dir+fileSep+"y.csv";
        String pathDye=dir+fileSep+"dye.csv";

        String dstDir="D:/tmp/dstdye";
        String dstTifDir="D:/tmp/dyetif";

        String pythoPath="D:/tmp/idw.py";

        String geoServerPath="D:\\geoserver-2.17.1\\data_dir\\data\\dyetif2";

//        String tableName="dye_shp_result_"+version;
//        String outTemFilePath="D:/tmp/"+tableName+".csv";

        Calendar calendar=Calendar.getInstance();
        calendar.setTime(dt);
        //处理dye浓度数据
        deleteFile(dstDir,dstTifDir);
        prcossDyePoint(calendar,pathLont,pathLat,pathDye,dstDir);
        executePyToInterPolate(pythoPath);
        copyFileToGeoserver(dstTifDir,geoServerPath);
        dumpTif(dstTifDir,version);
        deleteFile(dstDir,dstTifDir);
    }

    /**
     * 删除临时文件
     * @param shpDir 生成的shp文件
     * @param tifDir 生成的tif文件
     */
    private static void deleteFile(String shpDir,String tifDir){
        File shpFile=new File(shpDir);
        if(shpFile.isDirectory()){
            File[] shpFiles=shpFile.listFiles();
            for (int i=0;i<shpFiles.length;i++){
                shpFiles[i].delete();
            }
        }
        File tfiFile=new File(tifDir);
        if(tfiFile.isDirectory()){
            File[] tifFiles=tfiFile.listFiles();
            for (int i=0;i<tifFiles.length;i++){
                tifFiles[i].delete();
            }
        }
    }

    /**
     * 将生成的tif拷贝至geoserver
     * @param srcDir
     * @param dstDir
     */
    private static void copyFileToGeoserver(String srcDir,String dstDir){
        File srcFileDir=new File(srcDir);
        if(srcFileDir.isDirectory()){
            File[] files=srcFileDir.listFiles();
            for (File file:files){
                if(file.getName().endsWith("tif")){
                    insertTableName(file.getName());
                    Utils.copy(file.getAbsolutePath(),dstDir+File.separator+file.getName());
                }
            }
        }
    }


    /**
     * tif 数据插入数据表
     * @param fileName
     */
    private static void insertTableName(String fileName){
        String dtmStr=fileName.substring(0,12);
        int elevation=Integer.parseInt(fileName.substring(13,15));
        String sql="insert into dyetif2(location,ingestion,elevation)\n" +
                "values('"+fileName+"', to_timestamp('"+dtmStr+"','yyyyMMddHH24mi'),"+elevation+") on conflict(location) do nothing;";
        SqlSessionFactoryUtil.excuteUpdateSql(sql);
    }

    //读取dye数据，并生成点shp
    public static void prcossDyePoint(Calendar calendar, String pathLont, String pathLat, String pathDye, String dstDir){
        double[][] lonts = Utils.readTxtToArray(pathLont);
        double[][] lats = Utils.readTxtToArray(pathLat);
        File outFile=new File(dstDir);
        if(!outFile.exists()){
            outFile.mkdirs();
        }
        try {
            File file = new File(pathDye);
            String encoding = "UTF-8";
            if (file.isFile() && file.exists()) {
                InputStreamReader read = new InputStreamReader(
                        new FileInputStream(file), encoding);
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = "";
                int layer=1;
                int tm=1;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    if(lineTxt.length()==0){
                        layer=1;
                        tm++;
                        calendar.add(Calendar.HOUR,1);
                        System.out.println("时刻:"+tm);
                        continue;
                    }

                    String[] myArray=lineTxt.trim().split(",");
                    List<Double> lineList = new ArrayList<Double>();
                    for (String str : myArray) {
                        double dye=Math.abs(Double.parseDouble(str));
                        lineList.add(dye);
                    }
                    createDyeShp(calendar,layer,lonts[0],lats[0],lineList,dstDir);
                    layer++;
                }
                read.close();

            } else {
                System.out.println("文件不存在!");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 生成点shp
    private static void createDyeShp(Calendar calendar,int layer,double[] lonts,double[] lats,List<Double> dye,String dstDir){

        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMddHHmm");
        String eleFix=new DecimalFormat("00").format(layer);
        String shpPath=dstDir+java.io.File.separator+simpleDateFormat.format(calendar.getTime())+"_"+eleFix+".shp";
        int n=0;
        for (int i=0;i<lonts.length;i++){
            if(dye.get(i)==0)continue;
            n++;
        }
        if(n<5)return;
        ogr.RegisterAll();
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");//路径中支持中文
        gdal.SetConfigOption("SHAPE_ENCODING", "CP936");// shp属性中支持中文
//        gdal.SetConfigOption("GDAL_DATA","D:\\release-1900-x64-gdal-3-0-2-mapserver-7-4-2\\bin\\gdal-data");

        String strDriverName = "ESRI Shapefile";
        org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
        if (oDriver == null) {
            System.out.println(shpPath + " 驱动不可用！\n");
            return;
        }
        DataSource oDS = oDriver.CreateDataSource(shpPath, null);
        if (oDS == null) {
            System.out.println("创建矢量文件【" + shpPath + "】失败！\n");
            return;
        }




        // 创建图层，创建一个多边形图层，这里没有指定空间参考，如果需要的话，需要在这里进行指定
        //如果是mif或者tab，其实是可以多元素混合存放的，shp每个图层只能存放点线面中的一种。
        //所以tab创建图层的时候，选择什么都不影响后面的操作和存储结果
        SpatialReference spatialReference = new SpatialReference();
        spatialReference.ImportFromEPSG(4326);

        Layer oLayer =oDS.CreateLayer("TestPoint", spatialReference, ogr.wkbPoint, null);
        if (oLayer == null) {
            System.out.println("图层创建失败！\n");
            return;
        }


        // 先创建一个叫FieldID的整型属性
        FieldDefn oFieldID = new FieldDefn("dye", ogr.OFTReal);
        oLayer.CreateField(oFieldID, 1);

        FeatureDefn oDefn = oLayer.GetLayerDefn();

        for (int i=0;i<lonts.length;i++){
            if(dye.get(i)==0)continue;
            Feature oFeatureTriangle = new Feature(oDefn);
            oFeatureTriangle.SetField(0, dye.get(i));
            Geometry geomTriangle = Geometry.CreateFromWkt("POINT ("+lonts[i]+" "+lats[i]+")");
            oFeatureTriangle.SetGeometry(geomTriangle);
            oLayer.CreateFeature(oFeatureTriangle);
        }

        oDS.SyncToDisk();

        System.out.println(shpPath+" created");
    }


    /**
     *  调用程序执行python文件
     */
    public static void executePyToInterPolate(String pythonPath) {
        // TODO Auto-generated method stub
        Process proc;
        try {
            String[] args1 = new String[] { "python.exe", pythonPath,"test"};//python.exe处为你系统中python的安装位置；python.py为想要执行的python文件位置；test为想要传的参数
            //proc = Runtime.getRuntime().exec("python.exe python.py ");// 执行py文件 不传参数
            proc=Runtime.getRuntime().exec(args1);
            //用输入输出流来截取结果
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            in.close();
            proc.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //6.将tif栅格文件出入dye_tif_yyyymmdd中，点线钻取查询用
    public static void dumpTif(String tifDir,String version){
        String tableName="dye_tif_"+version;
        String sql="DROP TABLE IF EXISTS "+tableName;
        SqlSessionFactoryUtil.excuteUpdateSql(sql);
        String cmd="raster2pgsql -s 4326 -I -C -M "+tifDir+ File.separator+"*.tif  -F public."+tableName+" | psql -h localhost -p 5432 \"dbname=Bus user=postgres password=asa1234\"  \n";
        try {
            System.out.println(cmd);
            runCMD2(cmd);
            sql="alter table "+tableName+" add COLUMN tm TIMESTAMP(0);\n" +
                    "alter table "+tableName+" add COLUMN elevation int2;\n" +
                    "update  "+tableName+" set tm=to_timestamp(substr(filename,0,13),'yyyyMMddHH24mi'),elevation=substr(filename,14,2)::int2;";
            System.out.println(sql);
            SqlSessionFactoryUtil.excuteUpdateSql(sql);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * shp 浓度点空间插值生成tif
     */
    public static void  interpolateToTiff(String inPath,String outPath){
        File outDirFile=new File(outPath);
        if(!outDirFile.exists()){
            outDirFile.mkdir();
        }
        File file=new File(inPath);
        File[] files=file.listFiles();
        for (int i=0;i<files.length;i++){
            if(files[i].getName().endsWith("shp")){
                String conmand="gdal_grid -zfield dye  -of GTiff -ot Float32  -txe 105.59500926 109.94270074 -tye 16.13244326 21.91781758 -outsize 251 334 -l" +
//                  String conmand="gdal_grid -zfield dye  -of GTiff -ot Float32  -outsize 502 668 -l" +
//                  String conmand="gdal_grid -zfield \"dye\" -of GTiff -ot Float16  -txe 105.59500926 109.94270074 -tye 16.13244326 21.91781758 -outsize 251 334 -l" +
                        " "+files[i].getName().replace(".shp","")+" -a invdist:power=2.0:radius1=0.0062148:radius2=0.0062148:max_points=12 "
                        +files[i].getAbsolutePath()+" "+outPath+ File.separator+files[i].getName().replace(".shp",".tif");
                if(!files[i].getName().contains("202005070700-")){
                    continue;
                }
                System.out.println(conmand);
                try {
                    runCMD(conmand);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    //这个方法比第一个好，执行时不会卡  stmt要执行的命令
    public static void runCMD2(String stam){
        BufferedReader br = null;
        try {
            Random random=new Random();int n=random.nextInt();
            File tmpFile = new File(n+"temp.tmp");//新建一个用来存储结果的缓存文件

            if(!tmpFile.exists()) {
                tmpFile.createNewFile();
            }
            ProcessBuilder pb = new ProcessBuilder().command("cmd.exe", "/c", stam).inheritIO();
            pb.redirectErrorStream(true);//这里是把控制台中的红字变成了黑字，用通常的方法其实获取不到，控制台的结果是pb.start()方法内部输出的。
            pb.redirectOutput(tmpFile);//把执行结果输出。
            pb.start().waitFor();//等待语句执行完成，否则可能会读不到结果。
            InputStream in = new FileInputStream(tmpFile);
            br= new BufferedReader(new InputStreamReader(in,"utf-8"));
            String line = null;
            while((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
            br = null;
            tmpFile.delete();
            System.out.println("执行完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //执行cmd命
    public static boolean runCMD(String cmd) throws IOException, InterruptedException, IOException {
        final String METHOD_NAME = "runCMD";
        String[] command = {"cmd", "/c", cmd};
        Process p = Runtime.getRuntime().exec(command);
        BufferedReader br = null;
        try {
            consumeInputStream(p.getInputStream());
            consumeInputStream(p.getErrorStream());
            p.waitFor();
            int i = p.exitValue();
            System.out.println(METHOD_NAME + "#exitValue = " + i);
            if (i == 0) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            System.out.println(METHOD_NAME + "#ErrMsg=" + e.getMessage());
            e.printStackTrace();
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }
    }
    /**
     * 消费inputstream，并返回
     */
    public static void consumeInputStream(InputStream is) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
        String s;
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
    }

    /**
     *  dye 浓度入库方式2
     * @param calendar
     * @param layer
     * @param dye 浓度值列表
     * @param outTemFilePath 临时写入文件路径
     */
    private static void writeDyeData2File(Calendar calendar,int layer,List<Double> dye,String outTemFilePath){

        calendar.set(Calendar.MILLISECOND,0);
        java.sql.Date dt=new java.sql.Date(calendar.getTime().getTime());
        Time tm=new java.sql.Time(calendar.getTime().getTime());
        try {
            FileWriter fileWriter = new FileWriter(outTemFilePath, true);
            for (int i=0;i<dye.size();i++){
                if(dye.get(i)==0)continue;
                HashMap map=new HashMap();
                map.put("dt",dt);
                map.put("tm",tm);
                map.put("layer",layer);
                map.put("id",i);
                map.put("dye",dye.get(i));

                StringBuilder sb = new StringBuilder(dt + ",");
                sb.append(tm + ",");
                sb.append(layer + ",");
                sb.append(i + ",");
                sb.append(dye.get(i));
                sb.append(System.lineSeparator());
                fileWriter.write(sb.toString());
            }
            fileWriter.flush();
            fileWriter.close();

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 入库
     * @param tableName 表明
     * @param outFilePath 临时文件路径
     */
    private static void dumpDyeShp(String tableName,String outFilePath){
        String sql="copy "+tableName+" from '"+outFilePath+"'  DELIMITER ',' csv header";
        System.out.println("执行入库:"+sql);
        SqlSessionFactoryUtil.excuteUpdateSql(sql);
        System.out.println("入库完成");
    }

}
